﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Engine.Dtd.Schema;

namespace Engine.Sgml.Matching {
    internal sealed class SequenceModelMatcher {
        private ModelMatcher matcher;

        public SequenceModelMatcher(ModelMatcher matcher) {
            this.matcher = matcher;
            }

        public void Match(ref Match match, ref SElement element, DContentModel contentModel) {
            IModelGroupsNode groupItem = match.Model.FirstItem;
            while (true) {
                if (contentModel.Exclusions.Contains(element.DName)) {
                    MatchFinalizer.Finalize(match, groupItem);
                    break;
                    }
                if (groupItem.IsModelGroups()) {
                    Match inner = new Match(groupItem.FirstItem.Parent, element.Parent, match);
                    matcher.Match(inner, ref element, contentModel);
                    if (inner.HasMatches) {
                        match.Captures.Add(inner, true);
                        matcher.MatchRepetitive(match, inner.Model, ref element, contentModel);
                        }
                    else
                        match.Captures.Add(inner, false);
                    groupItem = groupItem.NextItem();
                    }
                else if (ElementMatcher.Match(element, groupItem)) {
                    match.Captures.Add(groupItem, element);
                    element = element.NextNode;
                    if (groupItem.CanRecur()) {
                        while (element != null) {
                            if (ElementMatcher.Match(element, groupItem))
                                match.Captures.Add(groupItem, element);
                            else if (contentModel.Inclusions.Contains(element.DName))
                                match.Captures.Add(InclusionNode.Instance, element);
                            else
                                break;
                            element = element.NextNode;
                            }
                        }
                    else
                        ModelMatcher.MatchInclusions(match, ref element, contentModel);
                    groupItem = groupItem.NextItem();
                    }
                else if (contentModel.Inclusions.Contains(element.DName)) {
                    match.Captures.Add(InclusionNode.Instance, element);
                    element = element.NextNode;
                    ModelMatcher.MatchInclusions(match, ref element, contentModel);
                    }
                else {
                    match.Captures.Add(groupItem);
                    groupItem = groupItem.NextItem();
                    }
                if (groupItem == null || element == null) {
                    MatchFinalizer.Finalize(match, groupItem);
                    break;
                    }
                }
            }
        }
    }